#include "stdafx.h"
#include "TxnMgr.h"
#include "Txn.h"

std::set<TxnMgr*>TxnMgr::m_s_TxnMgrs;

TxnMgr::TxnMgr(void):m_pActiveTxn(NULL)
{
	m_s_TxnMgrs.insert(this);
}

TxnMgr::~TxnMgr(void)
{
	std::set<TxnMgr*>::iterator it = m_s_TxnMgrs.find(this);
	TXN_ASSERT(it != m_s_TxnMgrs.end());
	if(it != m_s_TxnMgrs.end()) m_s_TxnMgrs.erase(it);

	for(std::vector<Txn*>::iterator it = m_vTxn.begin(); it != m_vTxn.end(); it++)
		delete (*it);
	m_vTxn.clear();

	for(std::vector<Txn*>::iterator it = m_vTxnUndo.begin(); it != m_vTxnUndo.end(); it++)
		delete (*it);
	m_vTxnUndo.clear();	
}

TxnMgr* TxnMgr::Get()
{
	static TxnMgr defaultTxnMgr;
	return &defaultTxnMgr;
}

Txn* TxnMgr::GetActiveTxn()
{
	std::set<TxnMgr*>::iterator it;
	for (it = m_s_TxnMgrs.begin(); it != m_s_TxnMgrs.end(); ++it)
	{
		Txn* pTxn = (*it)->ActiveTxn();
		if (pTxn) return pTxn;
	}
	return  NULL;
}

// Create a new transaction and add it into the list
Txn* TxnMgr::Add()
{
	Txn* pTxn = NULL;
	int iTxnId = 1;
	while(true)
	{
		pTxn = Get(iTxnId);
		if(!pTxn)
			break;
		else
			iTxnId++;
	}

	return Add(iTxnId);
}

// Get the active transaction
Txn* TxnMgr::ActiveTxn() const
{
	return m_pActiveTxn;
}

// Start transaction
BOOL TxnMgr::StartTxn(Txn* pTxn /*=NULL*/)
{
	if(m_pActiveTxn)
		m_pActiveTxn->Abort();
	if(!pTxn)
		pTxn = Add();
	m_pActiveTxn = pTxn;
	return pTxn->Start();
}

// End transaction
BOOL TxnMgr::EndTxn()
{
	BOOL bOK = FALSE;
	if(m_pActiveTxn)
	{
		bOK = m_pActiveTxn->End();
		m_pActiveTxn = NULL;

		TruncateUndoRedo();
	}
	else
		TXN_ASSERT(0);

	return bOK;
}

// Abort transaction
BOOL TxnMgr::AbortTxn()
{
	BOOL bOK = FALSE;
	if(m_pActiveTxn)
	{
		bOK = m_pActiveTxn->Abort();
		m_pActiveTxn = NULL;
	}
	else
		TXN_ASSERT(0);

	return bOK;
}

// Undo transaction
BOOL TxnMgr::UndoTxn()
{
	BOOL bOK = FALSE;
	if(!m_pActiveTxn && m_vTxn.size()>0)
	{
		Txn* pTxn = m_vTxn.back();
		if(pTxn)
		{
			// Undo the transaction
			bOK = pTxn->Undo();

			if(bOK)
			{
				// Erase the last item
				m_vTxn.pop_back();

				// Push the transaction into undone list
				m_vTxnUndo.push_back(pTxn);
			}
		}
	}
	return bOK;
}

// Redo transaction
BOOL TxnMgr::RedoTxn()
{
	BOOL bOK = FALSE;
	if(!m_pActiveTxn && m_vTxnUndo.size()>0)
	{
		Txn* pTxn = m_vTxnUndo.back();;

		if(pTxn)
		{
			// Redo the transaction
			bOK = pTxn->Redo();

			if(bOK)
			{
				// Erase 
				m_vTxnUndo.pop_back();

				// Push the transaction into transaction list
				m_vTxn.push_back(pTxn);
			}
		}
	}
	return bOK;
}

// Get a transaction from the list upon the TxnId
Txn* TxnMgr::Get(int iTxnId) const
{
	for(std::vector<Txn*>::const_iterator it = m_vTxn.begin(); it != m_vTxn.end(); it++)
	{
		if((*it)->GetId() == iTxnId)
			return (*it);
	}

	return NULL;
}

// Create a new transaction and add it into the list
Txn* TxnMgr::Add(int iTxnId)
{
	Txn* pTxn = new Txn(iTxnId);
	if(pTxn)
		m_vTxn.push_back(pTxn);

	return pTxn;
}

void TxnMgr::TruncateUndoRedo()
{
	std::vector<Txn*>::iterator it;
	for (it = m_vTxnUndo.begin(); it != m_vTxnUndo.end(); it++)
	{
		delete *it;
	}
	m_vTxnUndo.clear();
}